﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnvDTE;
using EnvDTE80;

namespace SinacorRules
{
    [BaseAddIn.Rules.DoubleClass("Rule_EventHandlerSuffix")]
    public sealed class Rule_EventHandlerSuffix_AddIn : BaseAddIn.Rules.BaseRuleAddIn
    {
        public Rule_EventHandlerSuffix_AddIn()
            : base("EventHandlerSuffix", 
                   "SinacorRules.SinacorRules", 
                   typeof(Rule_EventHandlerSuffix_AddIn).Assembly)
        {
        }

        protected sealed override void Check(CodeProperty propriedade, CodeNamespace namespaceElement, CodeClass2 classe)
        {
            Type tipo;
            
            if (propriedade.Type.TypeKind != vsCMTypeRef.vsCMTypeRefArray)
            {
                tipo = Type.GetType(String.Concat(propriedade.Type.CodeType.Namespace.FullName, ".", propriedade.Type.CodeType.Name));
            }
            else
            {
                tipo = Type.GetType(String.Concat(propriedade.Type.ElementType.CodeType.Namespace.FullName, ".", propriedade.Type.ElementType.CodeType.Name, "[]"));
            }

            if (AnalisaEventHandler(tipo))
            {
                GeraProblemaAddIn(propriedade.StartPoint.Parent.Parent.FullName,
                                  propriedade.StartPoint.Line,
                                  propriedade.StartPoint.DisplayColumn,
                                  "EventHandlerSuffixResolution",
                                  classe.Name,
                                  propriedade.Name,
                                  namespaceElement.Name);
            }
        }

        protected sealed override void Check(CodeVariable variavel, CodeNamespace namespaceElement, CodeClass2 classe)
        {
            Type tipo;

            if (variavel.Type.TypeKind != vsCMTypeRef.vsCMTypeRefArray)
            {
                tipo = Type.GetType(String.Concat(variavel.Type.CodeType.Namespace.FullName, ".", variavel.Type.CodeType.Name));
            }
            else
            {
                tipo = Type.GetType(String.Concat(variavel.Type.ElementType.CodeType.Namespace.FullName, ".", variavel.Type.ElementType.CodeType.Name, "[]"));
            }

            if (AnalisaEventHandler(tipo))
            {
                GeraProblemaAddIn(variavel.StartPoint.Parent.Parent.FullName,
                                  variavel.StartPoint.Line,
                                  variavel.StartPoint.DisplayColumn,
                                  "EventHandlerSuffixResolution",
                                  classe.Name,
                                  variavel.Name,
                                  namespaceElement.Name);
            }
        }

        private bool AnalisaEventHandler(Type tipo)
        {
            bool retorno = false;
            System.Reflection.MethodInfo metodo;
            System.Reflection.ParameterInfo[] parametrosMetodo;

            if (tipo != null)
            {
                if (tipo == typeof(System.EventHandler)
                            || tipo.IsSubclassOf(typeof(System.EventHandler)))
                {
                    retorno = true;
                }
                else
                {
                    metodo = tipo.GetMethod("Invoke");

                    if (metodo != null)
                    {
                        parametrosMetodo = metodo.GetParameters();

                        if (parametrosMetodo != null
                            && parametrosMetodo.Length == 2)
                        {
                            if (parametrosMetodo[0].ParameterType == typeof(System.Object)
                                || parametrosMetodo[0].ParameterType.IsSubclassOf(typeof(System.Object)))
                            {
                                if (parametrosMetodo[1].ParameterType == typeof(System.EventArgs)
                                || parametrosMetodo[1].ParameterType.IsSubclassOf(typeof(System.EventArgs)))
                                {
                                    retorno = true;
                                }
                            }
                        }
                    }
                }
            }

            return retorno;
        }
    }
}
